﻿using AutoMapper;
using CK.Sprite.Cache;
using CK.Sprite.Framework;
using JetBrains.Annotations;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace CK.Sprite.Form.Core
{
    public class SpriteFormLocalCache : LocalCache<SpriteFormVueDto>
    {
        public override string CacheKey => CommonConsts.SpriteFormCacheKey;

        public override Dictionary<Guid, SpriteFormVueDto> GetAllDict(string applicationCode)
        {
            if (!LocalCacheContainer.IsEnabledLocalCache)
            {
                return _serviceProvider.DoDapperService(DefaultDbConfig, (unitOfWork) =>
                {
                    return GetSpriteFormVueDtos(applicationCode, unitOfWork);
                });
            }
            else
            {
                return (Dictionary<Guid, SpriteFormVueDto>)LocalCacheContainer.Get($"{CommonConsts.SpriteFormCachePreKey}-{applicationCode}_{CacheKey}", key =>
                {
                    return _serviceProvider.DoDapperService(DefaultDbConfig, (unitOfWork) =>
                    {
                        return GetSpriteFormVueDtos(applicationCode, unitOfWork);
                    });
                });
            }
        }

        private Dictionary<Guid, SpriteFormVueDto> GetSpriteFormVueDtos(string applicationCode, IUnitOfWork unitOfWork)
        {
            var spriteFormRepository = ConnectionFactory.GetConnectionProvider(DefaultDbConfig.ConnectionType).GetRepository<ISpriteFormRepository>(unitOfWork);
            var spriteForms = spriteFormRepository.GetAllSpriteFormByApplicationCode(applicationCode);

            var results = new Dictionary<Guid, SpriteFormVueDto>();
            foreach (var spriteForm in spriteForms)
            {
                var spriteFormVueDto = new SpriteFormVueDto()
                {
                    Id = spriteForm.Id,
                    ApplicationCode = spriteForm.ApplicationCode,
                    Name = spriteForm.Name,
                    Version = spriteForm.Version,
                    FormType = spriteForm.FormType,
                    PropertySettings = string.IsNullOrEmpty(spriteForm.PropertySettings) ? null : JsonConvert.DeserializeObject(spriteForm.PropertySettings),
                    MenuWrapConfigs = string.IsNullOrEmpty(spriteForm.MenuWrapConfigs) ? null : JsonConvert.DeserializeObject(spriteForm.MenuWrapConfigs),
                    Controls = string.IsNullOrEmpty(spriteForm.Controls) ? null : JsonConvert.DeserializeObject(spriteForm.Controls),
                    WrapInfos = string.IsNullOrEmpty(spriteForm.WrapInfos) ? null : JsonConvert.DeserializeObject(spriteForm.WrapInfos),
                    Rules = string.IsNullOrEmpty(spriteForm.Rules) ? null : JsonConvert.DeserializeObject(spriteForm.Rules),
                    FormItems = string.IsNullOrEmpty(spriteForm.FormItems) ? null : JsonConvert.DeserializeObject(spriteForm.FormItems)
                };

                spriteFormVueDto.Rules = SpriteLocalCacheHelper.MakeRules(spriteForm.Rules);

                var relasionInfos = new List<RelasionInfo>();
                SpriteLocalCacheHelper.MakeWrapInfos(spriteFormVueDto.WrapInfos, relasionInfos);
                SpriteLocalCacheHelper.MakeControls(spriteFormVueDto.Controls);

                if(spriteFormVueDto.FormItems != null)
                {
                    foreach (var formItem in (spriteFormVueDto.FormItems as JArray))
                    {
                        SpriteLocalCacheHelper.ChangeStringToObject(formItem, "propertySettings");
                        foreach (var formRow in (formItem["children"] as JArray))
                        {
                            SpriteLocalCacheHelper.ChangeStringToObject(formRow, "propertySettings");
                            foreach (var formCol in (formRow["children"] as JArray))
                            {
                                SpriteLocalCacheHelper.ChangeStringToObject(formCol, "propertySettings");
                                SpriteLocalCacheHelper.ChangeStringToObject(formCol, "labelSettings");
                                SpriteLocalCacheHelper.ChangeStringToObject(formCol, "controlSettings");
                                SpriteLocalCacheHelper.ChangeStringToObject(formCol, "express");
                                SpriteLocalCacheHelper.ChangeStringToObject(formCol, "wrapConfigs");
                                if (formCol["colType"].ToString() == "2") // view
                                {
                                    AddRelationInfos(relasionInfos, Guid.Parse(formCol["objId"].ToString()), 2);
                                }

                                if (formCol["colType"].ToString() == "3") // form
                                {
                                    AddRelationInfos(relasionInfos, Guid.Parse(formCol["objId"].ToString()), 1);
                                }
                            }
                        }
                    }
                }                

                spriteFormVueDto.RelationInfos = relasionInfos;

                results.Add(spriteFormVueDto.Id, spriteFormVueDto);
            }

            return results;
        }

        private void AddRelationInfos(List<RelasionInfo> relasionInfos, Guid id, int relationType)
        {
            if (!relasionInfos.Any(r => r.Id == id))
            {
                relasionInfos.Add(new RelasionInfo()
                {
                    Id = id,
                    RelationType = relationType
                });
            }
        }
    }
}
